#!/usr/bin/env python3 
# -*- coding:utf-8 -*-

from functools import reduce

"""
map()函数接收两个参数，一个是函数，一个是Iterable，map将传入的函数依次作用到序列的每个元素，并把结果作为新的Iterator返回

比如我们有一个函数f(x)=x2，要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上，就可以用map()实现

            f(x) = x * x

                  │
                  │
  ┌───┬───┬───┬───┼───┬───┬───┬───┐
  │   │   │   │   │   │   │   │   │
  ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼

[ 1   2   3   4   5   6   7   8   9 ]

  │   │   │   │   │   │   │   │   │
  │   │   │   │   │   │   │   │   │
  ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼

[ 1   4   9  16  25  36  49  64  81 ]

"""


def f(x):
    return x * x


li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
r = map(f, li)
print(list(r))
# [1, 4, 9, 16, 25, 36, 49, 64, 81]

# map()传入的第一个参数是f，即函数对象本身。由于结果r是一个Iterator，Iterator是惰性序列，因此通过list()函数让它把整个序列都计算出来并返回一个list
# map()作为高阶函数，事实上它把运算规则抽象了，因此，我们不但可以计算简单的f(x)=x2，还可以计算任意复杂的函数

# 把list所有数字转为字符串
strList = map(str, li)
print(strList)  # map object
print(list(strList))

# ---------------------------------------------------------------------------------------------------
# reduce把一个函数作用在一个序列[x1, x2, x3, ...]上，这个函数必须接收两个参数，reduce把结果继续和序列的下一个元素做累积计算
# 效果就是: reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# e.g 把序列[1, 3, 5, 7, 9]变换成整数13579
l = [1, 3, 5, 7, 9]


def fn(x, y):
    return x * 10 + y


print(reduce(fn, l))  # 等价于 fn(fn(fn(fn(1,3),5),7),9)


# 把str转换为int的函数

def char2num(s):
    digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    return digits[s]


print(reduce(fn, map(char2num, '13579')))

"""
利用map()函数，把用户输入的不规范的英文名字，变为首字母大写，其他小写的规范名字。输入：['adam', 'LISA', 'barT']，输出：['Adam', 'Lisa', 'Bart']：
"""


def letter_convert(s):
    name = str(s).lower()
    return name[:1].upper() + name[1:].lower()


print(list(map(letter_convert, ['adam', 'LISA', 'barT'])))

"""
编写一个prod()函数，可以接受一个list并利用reduce()求积
"""


def ji(x, y):
    return x * y


def prod(num_list):
    return reduce(ji, num_list)


print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))

"""
利用map和reduce编写一个str2float函数，把字符串'123.456'转换成浮点数123.456
"""


def str2float(str_float):
    digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

    def char2num(s):
        s = str(s)
        if s == ".":
            return "."
        return digits[s]

    def build(x, y):
        return x * 10 + y

    int_str = str_float.split(".")[0]
    double_str = str_float.split(".")[1]
    num_list1 = list(map(char2num, int_str))
    num_list2 = list(map(char2num, double_str))

    num1 = reduce(build, num_list1)
    num2 = reduce(build, num_list2)

    return num1 + num2 / pow(10, len(double_str))


print(str2float('123.456'))
